/**
 * @file driver.c
 * @author zhao yijing
 * @brief  驱动接口实现
 * @version 0.1
 * @date 2022-11-03
 * 
 * @copyright Copyright (c) 2022
 * 
 */
#include "driver.h"

static xfat_err_t xdisk_hw_open(xdisk_t *disk,
                                void *init_data);
static xfat_err_t xdisk_hw_close(xdisk_t *disk);
static xfat_err_t xdisk_hw_write_sector(xdisk_t *disk,
                                        uint8_t *buf,
                                        uint32_t start_sector,
                                        uint32_t count);
static xfat_err_t xdisk_hw_read_sector(xdisk_t *disk,
                                       uint8_t *buf,
                                       uint32_t start_sector,
                                       uint32_t count);

xdisk_driver_t vdisk_driver = {
    .open = xdisk_hw_open,
    .close = xdisk_hw_close,
    .write_sector = xdisk_hw_write_sector,
    .read_sector = xdisk_hw_read_sector
};

xdisk_driver_t *get_vdisk_drv(void)
{
    return &vdisk_driver;
}

/**
 * @brief  打开磁盘接口实现
 * @param  disk              磁盘设备
 * @param  init_data         初始化参数
 * @return xfat_err_t        成功 - (0)
 */
static xfat_err_t xdisk_hw_open(xdisk_t *disk,
                                void *init_data)
{
    const char *path = (const char *)init_data;
    FILE *file = fopen(path, "rb+");
    if (file == NULL)
    {
        // 磁盘文件打开失败
        printf("open file failed %s:%d\n", __FILE__, __LINE__);
        // 返回IO错误
        return FS_ERR_IO;
    }

    disk->data = file;
    disk->sector_size = 512; // 暂时认为单个扇区大小512字节

    fseek(file, 0, SEEK_END);
    disk->totle_sector = ftell(file) / disk->sector_size;
    return FS_ERR_OK;
}

/**
 * @brief  关闭磁盘设备接口实现
 * @param  disk              磁盘设备
 * @return xfat_err_t        成功 - (0)
 */
static xfat_err_t xdisk_hw_close(xdisk_t *disk)
{
    FILE *file = (FILE *)disk->data;
    fclose(file);
    return FS_ERR_OK;
}

/**
 * @brief  写磁盘接口实现
 * @param  disk              磁盘设备
 * @param  buf               写缓冲区
 * @param  start_sector      写起始扇区
 * @param  count             写入扇区数
 * @return xfat_err_t        成功 - (0)
 */
static xfat_err_t xdisk_hw_write_sector(xdisk_t *disk,
                                        uint8_t *buf,
                                        uint32_t start_sector,
                                        uint32_t count)
{
    uint32_t offset = start_sector * disk->sector_size;
    int err = 0;
    FILE *file = (FILE *)disk->data;

    err = fseek(file, offset, SEEK_SET);
    if (err < 0)
    {
        // 文件指针偏移错误
        printf("fseek failed %s:%d\n", __FILE__, __LINE__);
        // 返回IO错误
        return FS_ERR_IO;
    }

    err = fwrite(buf, disk->sector_size, count, file);
    if (err < 0)
    {
        // IO写文件失败
        printf("fwrite failed %s:%d\n", __FILE__, __LINE__);
        // 返回IO错误
        return FS_ERR_IO;
    }

    fflush(file);
    return FS_ERR_OK;
}

/**
 * @brief  读磁盘接口实现
 * @param  disk              磁盘设备
 * @param  buf               读缓冲区
 * @param  start_sector      读取起始扇区
 * @param  count             读取扇区数
 * @return xfat_err_t        成功 - (0)
 */
static xfat_err_t xdisk_hw_read_sector(xdisk_t *disk,
                                       uint8_t *buf,
                                       uint32_t start_sector,
                                       uint32_t count)
{
    uint32_t offset = disk->sector_size * start_sector;
    FILE *file = (FILE *)disk->data;
    int err = 0;

    err = fseek(file, offset, SEEK_SET);
    if (err < 0)
    {
        // 文件定位错误
        printf("fseek failed %s:%d\n", __FILE__, __LINE__);
        // 返回IO错误
        return FS_ERR_IO;
    }

    err = fread(buf, disk->sector_size, count, file);
    if (err < 0)
    {
        // 读文件错误
        printf("fread failed %s:%d\n", __FILE__, __LINE__);
        // 返回IO错误
        return FS_ERR_IO;
    }
    return FS_ERR_OK;
}
